#include "Log.hpp"
#include "Mutex.hpp"
#include <iostream>
#include <cstdlib>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
#include <thread>
#include <vector>
#include <cstring>

extern Log lg;

using namespace std;

// void *threadRun(void *args)
// {
//     while (1)
//     {
//         lg(Info, "new thread: %d", getpid());
//         sleep(1);
//     }

//     return nullptr;
// }

// int main()
// {
//     pthread_t tid;
//     pthread_create(&tid, nullptr, threadRun, nullptr);

//     while (1)
//     {
//         lg(Info, "main thread: %d", getpid());
//         sleep(1);
//     }

//     return 0;
// }

// void *threadRoutine(void *args)
// {
//     while (true)
//     {
//         lg(Info, "new thread, pid: %d", getpid());
//         sleep(2);
//     }
// }
// int main()
// {
//     pthread_t tid;
//     pthread_create(&tid, nullptr, threadRoutine, nullptr);

//     while (true)
//     {
//         lg(Info, "main thread, pid: %d", getpid());
//         sleep(1);
//     }

//     return 0;
// }

// void show(const string &name)
// {
//     lg(Info, "%s say: hello thread", name.c_str());
// }

// void *threadRoutine(void *args)
// {
//     int n = 3;
//     while (true)
//     {
//         lg(Info, "new thread, pid: %d", getpid());
//         sleep(2);
//     }
// }

// int main()
// {
//     pthread_t tid;
//     pthread_create(&tid, nullptr, threadRoutine, nullptr);

//     lg(Debug, "new thread tid: 0x%x", tid);

//     while (true)
//     {
//         lg(Info, "main thread, pid: %d", getpid());
//         sleep(1);
//     }

//     return 0;
// }

// void *threadRoutine(void *threadname)
// {
//     (char*)threadname;
//     int n = 5;
//     while (true)
//     {
//         lg(Debug, "%s is running...", threadname);
//         sleep(1);
//         if (--n == 0)
//             break;
//     }

//     // 线程退出
//     lg(Info, "%s quit!", threadname);
//     return nullptr;
// }

// int main()
// {
//     pthread_t tid;
//     pthread_create(&tid, nullptr, threadRoutine, (void*)"thread 1");

//     pthread_join(tid, nullptr);

//     lg(Info, "main thread quit!");
//     return 0;
// }

// void *threadRoutine(void *threadname)
// {
//     (char*)threadname;
//     int n = 5;
//     while (true)
//     {
//         lg(Debug, "%s is running...", threadname);
//         sleep(1);
//         if (--n == 0)
//             break;
//     }

//     // 线程退出
//     lg(Info, "%s quit!", threadname);
//     pthread_exit((void*)2);
// }

// int main()
// {
//     pthread_t tid;
//     pthread_create(&tid, nullptr, threadRoutine, (void*)"thread 1");

//     void* retval;
//     pthread_join(tid, &retval);

//     lg(Info, "main thread quit, ret: %d", retval);
//     return 0;
// }

// class Request
// {
// public:
//     Request(int start, int end, const string &threadname)
//         :start_(start), end_(end), threadname_(threadname)
//     {}
// public:
//     int start_;
//     int end_;
//     string threadname_;
// };

// class Response
// {
// public:
//     Response(int result, int exitcode) 
//         :result_(result),exitcode_(exitcode)
//     {}
// public:
//     int result_;     //计算结果
//     int exitcode_;   //计算结果是否可靠
// };

// void *sumCount(void *args)
// {
//     Request *rq = static_cast<Request*>(args); // Request *rq = (Request*)args;
//     Response *rsp = new Response(0, 0);

//     for(int i = rq->start_; i < rq->end_; i++)
//     {
//         rsp->result_ += i;
//     }

//     delete rq;
//     return rsp;
// }

// int main()
// {
//     pthread_t tid;
//     Request *rq = new Request(1, 100, "thead 1");
//     pthread_create(&tid, nullptr, sumCount, rq);

//     void *retval;
//     pthread_join(tid, &retval);
//     Response *rsp = static_cast<Response*>(retval);
//     lg(Info, "rsp->result: %d, exitcode: %d", rsp->result_, rsp->exitcode_);
    
//     delete rsp;

//     return 0;
// }

// void threadrun()
// {
//     while (1)
//     {
//         cout << "this is a new thread in C++" << endl;
//         sleep(1);
//     }
// }

// int main()
// {
//     thread t1(threadrun);

//     t1.join();

//     return 0;
// }

// string toHex(pthread_t tid)
// {
//     char hex[64];
//     snprintf(hex, sizeof(hex), "%p", tid);
//     return hex;
// }

// void *threadRoutine(void *args)
// {
//     while(true)
//     {
//         sleep(1);
//         lg(Info, "thread id: %s", toHex(pthread_self()).c_str());
//     }
// }

// int main()
// {
//     pthread_t tid;
//     pthread_create(&tid, nullptr, threadRoutine, (void*)"thread 1");

//     lg(Info, "main-thread create thead done, new-thread id: %s", toHex(tid).c_str());
    
//     pthread_join(tid, nullptr);
//     return 0;
// };

// struct threadData
// {
//     string tid;
//     string threadname;
// };

// void InitThreadData(threadData *td, int number, pthread_t tid)
// {
//     td->threadname = "thread-" + to_string(number); // thread-0

//     char buffer[128];
//     snprintf(buffer, sizeof(buffer), "0x%x", tid);
//     td->tid = buffer;
// }

// __thread int g_val = 0;

// void *threadRoutine(void *args)
// {
//     threadData *td = static_cast<threadData*>(args);
    
//     // int i = 0;   
//     // while(i < 10)
//     // {
//     //     lg(Info, "pid: %d, tid: %s, threadname: %s, &i: %p", getpid(), td->tid.c_str(), td->threadname.c_str(), i);
//     //     sleep(1);
//     //     i++;
//     // }

//     delete td;
//     return nullptr;
// }

// int main()
// {
//     const int num = 10;
//     vector<pthread_t> tids;
//     for(int i = 0; i < num; i++)
//     {
//         pthread_t tid;
//         threadData *td = new threadData;
//         InitThreadData(td, i, tid);

//         pthread_create(&tid, nullptr, threadRoutine, td);
//         tids.push_back(tid);
//         // sleep(1);
//     }

//     for (auto i : tids)
//     {
//         pthread_detach(i);
//         lg(Info, "0x%x detach success!", i);
//     }

//     for(int i = 0; i < tids.size(); i++)
//     {
//         int n = pthread_join(tids[i], nullptr);
//         lg(Error, "n = %d, who = 0x%x, reason: %s", n, tids[i], strerror(n));
//     }
    
//     return 0;
// }

// class threadData
// {
// public:
//     threadData(int number)
//     {
//         threadname = "thread-" + to_string(number);
//     }
// public:
//     string threadname;
// };

// int tickets = 20;
// pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

// void* getTicket(void* args)
// {
//     threadData *td = static_cast<threadData *>(args);
//     const char *name = td->threadname.c_str();
//     while (true)
//     {
//         // pthread_mutex_lock(&lock);
//         LockGuard(&lock);
//         if(tickets > 0)
//         {
//             usleep(1000);
//             lg(Info, "%s get a ticket: %d", name, tickets);
//             tickets--;
//             // pthread_mutex_unlock(&lock);
//         }
//         else
//         {
//             // pthread_mutex_unlock(&lock);
//             break;
//         }
//         usleep(15);
//     }
    
//     lg(Info, "%s quit!", name);
    
//     return nullptr;
// }

// int main()
// {
//     const int num = 4;
//     vector<pthread_t> tids;
//     vector<threadData*> thread_datas;


//     for(int i = 1; i <= num; i++)
//     {
//         pthread_t tid;
//         threadData* td = new threadData(i);

//         thread_datas.push_back(td);
//         pthread_create(&tid, nullptr, getTicket, thread_datas[i-1]);
        
//         tids.push_back(tid);
//     }

//     for(auto thread : tids)
//         pthread_join(thread, nullptr);   
    
//     for(auto td : thread_datas)
//         delete td;
    
//     return 0;
// }

int cnt = 0;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

void *Count(void * args)
{
    pthread_detach(pthread_self());

    uint64_t number = (uint64_t)args;
    lg(Info, "pthread %d create success!", number);

    while (true)
    {
        pthread_mutex_lock(&lock);
        // 为什么在这个位置？
        // pthread_mutex_wait() 会让线程进行等待时，自动释放锁
        pthread_cond_wait(&cond, &lock);
        lg(Info, "pthread %d, cnt: %d", number, cnt);
        cnt++;
        pthread_mutex_unlock(&lock);
        sleep(1);
    }

    return nullptr;
}

int main()
{
    lg(Info, "main thread create success!");
    for(uint64_t i = 0; i < 5; i++)
    {
        pthread_t tid;
        pthread_create(&tid, nullptr, Count, (void*)i);
    }

    while (true) 
    {
        sleep(1);
        lg(Info, "signal one thread!");
        pthread_cond_signal(&cond); // 发出信号唤醒等待队列中的线程(默认是第一个)
    }

    return 0;
}